/*******************************************************************
 *
 * Copyright (C), 2021-2022, LS, All rights reserved.
 *
 * Author      : 
 * Create Time : 2021-09-17
 * Version     : v0.1
 * Description : 
 *******************************************************************/

/*********************************************************************
    INCLUDES
*/

#include "att.h"
#include "hci.h"
#include "ll_common.h"
#include "bcomdef.h"
#include "OSAL.h"
#include "linkdb.h"
#include "gatt.h"
#include "gapgattserver.h"
#include "gattservapp.h"
#include "gatt_profile_uuid.h"
#include "peripheral.h"
#include "gapbondmgr.h"
#include <string.h>
#include "log.h"

#include "osal_ble.h"
#include "sys_task.h"
#include "app_global_data.h"

#include "ble_app_util.h"
#include "ls_ble_custom.h"
#include "ls_ble_sdk_api.h"
#include "ls_ble_phy62xx.h"
#include "ls_ble_sdk_config.h"

/*********************************************************************
    MACROS
*/


/*********************************************************************
    CONSTANTS
*/

/*********************************************************************
    TYPEDEFS
*/

/*********************************************************************
    GLOBAL VARIABLES
*/

/*********************************************************************
    EXTERNAL VARIABLES
*/

/*********************************************************************
    EXTERNAL FUNCTIONS
*/

/*********************************************************************
    LOCAL FUNCTIONS
*/
static void param_update_cb(uint16 connInterval, uint16 connSlaveLatency, uint16 connTimeout);
static void osalBleGapStateCB( gaprole_States_t newState);

/*********************************************************************
    PROFILE CALLBACKS
*/
/*********************************************************************
    LOCAL VARIABLES
*/
uint8 osalBle_TaskID;   // Task ID for internal task/event processing
gaprole_States_t gapProfileState = GAPROLE_INIT;
static gapRolesParamUpdateCB_t param_update_cb_fun = param_update_cb;
/*********************************************************************/

// GAP Role Callbacks
static gapRolesCBs_t osalBlePeripheralCB =
{
    osalBleGapStateCB,  // Profile State Change Callbacks
    NULL                // When a valid RSSI is read from controller
};



void param_update_cb(uint16 connInterval, uint16 connSlaveLatency, uint16 connTimeout)
{
    LOG("conn param update: connInterval-%dms, latency-%d, timeout-%dms", \
        (uint16_t)(connInterval*1.25),  \
        (uint16_t)(connSlaveLatency),   \
        (uint16_t)(connTimeout*10) );
}


static void appbleProcOSALMsg( osal_event_hdr_t *pMsg )
{
	if(pMsg->event == GATT_MSG_EVENT) {
        gattMsgEvent_t *msg = (gattMsgEvent_t *)pMsg;
		if(msg->method == ATT_HANDLE_VALUE_CFM) {
            //LOG("ATT_HANDLE_VALUE_CFM.\n");
            custom_set_profile_cb_evt(CUSTOM_EVT_INDICATION_COMPLETE);
        }
	}
}


void osalBleInit(uint8 task_id)
{
    osalBle_TaskID = task_id;
    LOG("osalBleInit\n");
    
    // Setup the GAP
    VOID GAP_SetParamValue( TGAP_CONN_PAUSE_PERIPHERAL, 6 );    // Connection Pause Peripheral time value (in seconds)
    
    // Initialize GATT attributes
    GGS_AddService( GATT_ALL_SERVICES );         // GAP
    GATTServApp_AddService( GATT_ALL_SERVICES ); // GATT attributes
    ls_ble_sdk_service_init();

    llInitFeatureSet2MPHY(TRUE);
    llInitFeatureSetDLE(TRUE);
    ATT_SetMTUSizeMax(BLE_MTU_MAX_SIZE);
    LOG("[2Mbps | DLE | MTU %d] \n", BLE_MTU_MAX_SIZE);
    HCI_LE_SetDefaultPhyMode(0, 0, 0x01, 0x01);
    GAP_RegisterForHCIMsgs(osalBle_TaskID);
    GAPRole_RegisterAppCBs(&param_update_cb_fun);

    // Setup a delayed profile startup
    osal_set_event(osalBle_TaskID, START_DEVICE_EVT);
}


uint16 osalBleProcEvt( uint8 task_id, uint16 events )
{
    VOID task_id; // OSAL required parameter that isn't used in this function

    if ( events & SYS_EVENT_MSG )
    {
        uint8* pMsg;
        if ( (pMsg = osal_msg_receive( osalBle_TaskID )) != NULL )
        {
            appbleProcOSALMsg((osal_event_hdr_t*) pMsg);
            // Release the OSAL message
            VOID osal_msg_deallocate( pMsg );
        }
        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
    }

    if ( events & START_DEVICE_EVT )
    {
        // Start the Device
        VOID GAPRole_StartDevice(&osalBlePeripheralCB);
        HCI_LE_ReadResolvingListSizeCmd();  //MTU request need this.
        return ( events ^ START_DEVICE_EVT );
    }
    
    
    if( events & APP_BLE_RESEND_EVT )
    {
        app_ble_upload_resend_handle();
        return ( events ^ APP_BLE_RESEND_EVT );
    }

    
    if( events & APP_BLE_DELAY_SEND_EVT )
    {
        app_ble_upload_skip_result();
        return ( events ^ APP_BLE_DELAY_SEND_EVT );
    }
    
    
    if( events & APP_BLE_DELAY_UP_BATT )
    {
        sys_task_msg_send(MSG_TYPE_BG, BG_EVT_BLE_UPLOAD_BATT_PER);
        return ( events ^ APP_BLE_DELAY_UP_BATT );
    }
    
    
    if ( events & APP_BLE_RESET_ADV_EVT )
    {
        LOG("RESET_ADV_EVT: %d\n", ls_ble_start_adv());
        return ( events ^ APP_BLE_RESET_ADV_EVT );
    }

    return 0;
}



static void osalBleGapStateCB( gaprole_States_t newState )
{
    LOG("osalBleGapStateCB: %d\n", newState);

    gaprole_States_t g_gap_state_last = gapProfileState;
    gapProfileState = newState;
    
    switch (newState)
    {
        case GAPROLE_STARTED: {
			HCI_ReadBDADDRCmd();
        } break;
        
        case GAPROLE_ADVERTISING: {
         } break;
        
        case GAPROLE_CONNECTED: {
            ls_ble_sdk_cb_evt_param_t evt_param;
            evt_param.evt = LS_BLE_SDK_CB_EVT_CONNECT;
            evt_param.len = 0;
            ls_ble_sdk_callback(&evt_param);
        } break;
        
        case GAPROLE_WAITING:
        case GAPROLE_WAITING_AFTER_TIMEOUT: {
            if(g_gap_state_last == GAPROLE_CONNECTED) {          
                ls_ble_sdk_cb_evt_param_t evt_param;
                evt_param.evt = LS_BLE_SDK_CB_EVT_DISCONNECT;
                ls_ble_sdk_callback(&evt_param);
            }
            else if(g_gap_state_last == GAPROLE_ADVERTISING) {
                extern volatile bool g_is_restart_adv;
                if(g_is_restart_adv) {
                    g_is_restart_adv = false;
					LOG("GAPROLE_ADVERTISING\n");
                    if(DEV_MODE_SLEEP != g_app_data.sys.mode) {
                        ls_ble_start_adv();
                    }
                }
            }
        } break;
        
        default: {
        } break;
    }
}



/*********************************************************************
*********************************************************************/
